package com.gs.mp.db;

import com.google.common.collect.Lists;
import com.gs.common.tool.consts.DbDriverConst;
import com.gs.common.tool.pojo.OptionItem;
import com.gs.common.tool.utils.CollectionUtil;
import com.gs.common.tool.utils.SwingUtil;
import com.gs.mp.db.utils.GenerateJavaUtil;
import lombok.extern.slf4j.Slf4j;

import javax.swing.*;
import javax.swing.text.StyledDocument;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 启动类
 *
 * @author: guoshuai
 * @date: 2024/05/23 20:39
 **/
@Slf4j
public class App {

    private static final String fontName = "微软雅黑";


    public static void main(String[] args) {
        //使用事件调度线程确保所有的Swing组件都在AWT线程中安全地构建
        SwingUtilities.invokeLater(App::createJTextPaneAndShowGUI);
    }


    /**
     * 创建gui
     */
    private static void createJTextPaneAndShowGUI() {
        // 创建主窗口
        JFrame frame = new JFrame("mybatis-plus反向生成");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //创建GridBagLayout实例
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.fill = GridBagConstraints.BOTH;
        gbc.insets = new Insets(5, 5, 5, 5); // 内边距
        gbc.gridx = 0; // 列位置从0开始
        gbc.gridy = 0; // 行位置从0开始
        gbc.weightx = 0; // 水平权重
        gbc.weighty = 0; // 垂直权重

        // 添加GridBagLayout到窗口
        Container contentPane = frame.getContentPane();
        contentPane.setLayout(new GridBagLayout());

        // 第一行: JLabel和JComboBox
        JLabel label1 = new JLabel("数据库类型:");
        label1.setFont(new Font(fontName, Font.BOLD, 14));
        gbc.gridy = 0;
        contentPane.add(label1, gbc);
        gbc.gridx = 1; // 移动到下一列
        //当前目录
        //todo test
        //String basePath = "D:\\project\\test\\java-code-generator\\gen-template\\mybatis-plus-db-template";
        String basePath = System.getProperty("user.dir");
        //遍历驱动目录，填充下拉
        OptionItem[] drivers = getSelectList(basePath, "driver");
        JComboBox<OptionItem> comboBox1 = new JComboBox<>(drivers);
        contentPane.add(comboBox1, gbc);
        gbc.gridx = 0; // 重置回第一列
        gbc.gridy++; // 移动到下一行

        // 第二行: JLabel和JComboBox
        JLabel label2 = new JLabel("配 置 文 件:");
        label2.setFont(new Font(fontName, Font.BOLD, 14));
        contentPane.add(label2, gbc);
        gbc.gridx = 1;
        //初始化mysql
        //初始化默认mysql配置
        OptionItem[] cfFiles = getSelectList(basePath, DbDriverConst.MYSQL);
        JComboBox<OptionItem> comboBox2 = new JComboBox<>(cfFiles);
        contentPane.add(comboBox2, gbc);
        gbc.gridx = 0;
        gbc.gridy++;

        // 第三行: JButton
        JButton clickButton = new JButton("开始生成");
        contentPane.add(clickButton, gbc);
        gbc.gridy++;

        // 第四行: JTextArea
        gbc.gridx = 0;
        gbc.gridwidth = 2; // 跨两列
        gbc.weightx = 1; // 允许水平扩展
        gbc.weighty = 1; // 允许垂直扩展

        JTextPane textPane = new JTextPane();
        textPane.setEditable(false);
        JScrollPane scrollPane = new JScrollPane(textPane);
        contentPane.add(scrollPane, gbc);

        //获取StyledDocument用于格式化文本
        StyledDocument doc = textPane.getStyledDocument();
        //数据源切换事件
        comboBox1.addItemListener(e -> {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                //清空旧选项
                comboBox2.removeAllItems();
                //获取选中的项
                OptionItem selectedItem = (OptionItem) e.getItem();
                //System.out.println("选中数据源:\n" + selectedItem);
                //获取数据源下配置文件列表
                OptionItem[] selectList;
                try {
                    selectList = getSelectList(basePath, selectedItem.getValue());
                } catch (IllegalStateException ex) {
                    SwingUtil.writeErrorMsg(doc, ex.getMessage());
                    return;
                }
                //填充下拉框
                Arrays.stream(selectList).forEach(comboBox2::addItem);
            }
        });

        //按钮点击事件
        clickButton.addActionListener(e -> {
            try {
                //每次点击，先清空上次的文本
                doc.remove(0, doc.getLength());
                OptionItem dbType = (OptionItem) comboBox1.getSelectedItem();
                if (Objects.isNull(dbType)) {
                    SwingUtil.writeErrorMsg(doc, "请选择数据库类型!");
                    return;
                }
                OptionItem cfFileName = (OptionItem) comboBox2.getSelectedItem();
                if (Objects.isNull(cfFileName)) {
                    SwingUtil.writeErrorMsg(doc, "请选择配置文件!");
                    return;
                }
                //outputArea.append("当前目录: " + basePath + "\n");
                //调用生成java文件
                List<String> resultList = GenerateJavaUtil.generate(dbType.getValue(), cfFileName.getKey(), dbType.getKey());
                SwingUtil.writeRowsText(doc, resultList);
            } catch (Exception ex) {
                log.error("生成异常:", ex.getCause());
                SwingUtil.writeErrorMsg(doc, ex.getMessage());
            }
        });

        //自定义下拉框显示
        SwingUtil.showComboBox(comboBox1);
        SwingUtil.showComboBox(comboBox2);

        // 设置窗口大小并使其可见
        frame.pack(); // 自动调整窗口大小以适应其组件
        frame.setSize(800, 600); // 设置窗口初始大小
        frame.setVisible(true);
    }


    /**
     * 获取下拉元素
     *
     * @param basePath 基础路径
     * @param dirName  目录名
     */
    private static OptionItem[] getSelectList(String basePath, String dirName) {
        String dbPath = basePath + File.separator + dirName;
        //创建File对象表示目录
        File directory = new File(dbPath);
        //判断目录是否存在
        if (!directory.exists() || !directory.isDirectory()) {
            throw new IllegalStateException(String.format("%s目录不存在或不是一个有效的目录!", dbPath));
        }
        //获取目录下所有文件和目录
        File[] files = directory.listFiles();
        //输出目录中的文件和子目录名称
        if (files == null) {
            throw new IllegalStateException(String.format("%s目录下无配置文件!", dbPath));
        }
        boolean isDriver = "driver".equals(dirName);
        List<File> filesList;
        //配置文件必须以generator.xml结尾
        if (isDriver) {
            filesList = Lists.newArrayList(files);
        } else {
            filesList = Lists.newArrayList();
            //递归遍历目录查询文件
            for (File file : files) {
                if (file.isDirectory()) {
                    File[] subFiles = file.listFiles();
                    if (subFiles != null && subFiles.length > 0) {
                        filesList.addAll(Lists.newArrayList(subFiles));
                    }
                } else {
                    filesList.add(file);
                }
            }
            filesList.removeIf(d -> !d.getName().endsWith("generator.xml"));
            if (CollectionUtil.isEmpty(filesList)) {
                throw new IllegalStateException(String.format("%s目录下,未查到*.generator.xml文件!", dirName));
            }
        }
        return filesList.stream().map(file -> {
            OptionItem optionItem = new OptionItem();
            optionItem.setValue(file.getName()).setKey(file.getAbsolutePath());
            String name = file.getName();
            if (isDriver) {
                if (name.startsWith(DbDriverConst.MYSQL)) {
                    optionItem.setValue(DbDriverConst.MYSQL);
                } else if (name.startsWith(DbDriverConst.POSTGRESQL)) {
                    optionItem.setValue(DbDriverConst.POSTGRESQL);
                } else if (name.startsWith(DbDriverConst.SQL_SERVER)) {
                    optionItem.setValue(DbDriverConst.SQL_SERVER);
                }
            }
            return optionItem;
        }).toArray(OptionItem[]::new);
    }
}
